﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace JavaDocToXmlComment
{
    class Program
    {
        /// <summary>
        /// Represents a regEx pattern which identifies beginning tags in JavaDoc comments.
        /// </summary>
        private static Regex _javaDocPatternBeginningTag = new Regex(@"(\t{0,})\/\*\*\n", RegexOptions.Compiled);

        /// <summary>
        /// Represents a regEx pattern which identifies middle tags in JavaDoc comments.
        /// </summary>
        private static Regex _javaDocPatternMiddleTag = new Regex(@"(\t{0,}) \* ", RegexOptions.Compiled);

        /// <summary>
        /// Represents a regEx pattern which identifies ending tags in JavaDoc comments.
        /// </summary>
        private static Regex _javaDocPatternEndingTag = new Regex(@"(\t{0,}) \*/.*\n", RegexOptions.Compiled);

        /// <summary>
        /// Represents a regEx pattern which identifies parameters and its comments.
        /// </summary>
        private static Regex _javaDocPatternParam = new Regex(@"@param\s(\w{0,})\s?(.*)$", RegexOptions.Compiled | RegexOptions.Multiline);

        /// <summary>
        /// Represents a regEx pattern which identifies parameters and its comments.
        /// </summary>
        private static Regex _javaDocPatternReturn = new Regex(@"@return\s?(([\w|\s]{0,}))$", RegexOptions.Compiled | RegexOptions.Multiline);

        /// <summary>
        /// Represents a regEx pattern which identifies parameters its author.
        /// </summary>
        private static Regex _javaDocPatternAuthor = new Regex(@"@author\s?(([\w|\s]{0,}))$", RegexOptions.Compiled | RegexOptions.Multiline);

        /// <summary>
        /// Represents a regEx pattern which identifies entire parameter line 
        /// </summary>
        private static Regex _xmlCommentsParamLine = new Regex("^.*<param name=\"\\w{0,}\">.*<\\/param>.*$", RegexOptions.Compiled | RegexOptions.Multiline);

        /// <summary>
        /// Represents a regEx pattern which identifies entire returns line 
        /// </summary>
        private static Regex _xmlCommentsReturnsLine = new Regex("^.*<returns>.*<\\/returns>.*$", RegexOptions.Compiled | RegexOptions.Multiline);

        /// <summary>
        /// Represents a regEx pattern which identifies ending tag
        /// </summary>
        private static Regex _xmlCommentsEndingTag = new Regex(@"^.*<\/summary>.*$", RegexOptions.Compiled | RegexOptions.Multiline);

        /// <summary>
        /// Represents a regEx pattern which identifies all the tag, separeting the content from the markup marks.
        /// </summary>
        private static Regex _xmlCommentsEntireTag = new Regex(@"(\t{0,}\/\/\/\s(.*)){1,}", RegexOptions.Compiled);

        /// <summary>
        /// Represents a regEx pattern which identifies the markup comment mark.
        /// </summary>
        private static Regex _xmlCommentsMarkup = new Regex(@"\t{0,}\/\/\/\s", RegexOptions.Compiled);

        /// <summary>
        /// Represents a regEx pattern which identifies an element.
        /// </summary>
        private static Regex _xmlCommentsJustElement = new Regex(@"\t{0,}\/\/\/\s(<.*>)", RegexOptions.Compiled);

        /// <summary>
        /// This is the start point
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            try
            {
                #region Entries validation

                if (args == null)
                {
                    throw new ArgumentNullException("args");
                }
                if (args.Length == 0)
                {
                    throw new ArgumentException("Do you need to specify a local to conversion");
                }

                #endregion

                DoConversion(
                    new DirectoryInfo(args[0]));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// Do the conversion
        /// </summary>
        /// <param name="directory"></param>
        private static void DoConversion(DirectoryInfo directory)
        {
            #region Entries validation

            if (directory == null)
            {
                throw new ArgumentNullException("directory");
            }

            #endregion

            foreach (var item in directory.GetDirectories())
            {
                #region Entries validation

                if (item == null)
                {
                    throw new ArgumentNullException("item");
                }

		        #endregion

                foreach (var file in item.GetFiles())
                {
                    String contend = GetReplacedString(file);

                    using (StreamWriter writer = new StreamWriter(file.FullName, false))
                    {
                        writer.Write(contend);
                    }
                }

                DoConversion(item);
            }
        }

        /// <summary>
        /// Returns a replaced string
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        private static string GetReplacedString(FileInfo file)
        {
            String content = null;
            using (var stream = file.OpenText())
            {
                content = stream.ReadToEnd();
            }

            #region Entries validation

            if (String.IsNullOrEmpty(content))
            {
                return "";
            }

		    #endregion

            #region Changing JavaDoc to XmlComment

            // Removing the beginning tag
            if (_javaDocPatternBeginningTag.IsMatch(content))
            {
                content =
                    _javaDocPatternBeginningTag.Replace(content, "");
            }
            // Replacing the middle tag
            if (_javaDocPatternMiddleTag.IsMatch(content))
            {
                content =
                    _javaDocPatternMiddleTag.Replace(content, new MatchEvaluator(delegate(Match match)
                    {
                        return match.Groups[1].Value + "/// ";
                    }));
            }
            // Removing the ending tag
            if (_javaDocPatternEndingTag.IsMatch(content))
            {
                content =
                    _javaDocPatternEndingTag.Replace(content, "");
            }
            // Replacing the parameters
            if (_javaDocPatternParam.IsMatch(content))
            {
                content =
                    _javaDocPatternParam.Replace(content, new MatchEvaluator(delegate(Match match)
                    {
                        return "<param name=\"" + match.Groups[1].Value + "\">" + match.Groups[2].Value + "</param>";
                    }));
            }
            // Replacing the returns
            if (_javaDocPatternReturn.IsMatch(content))
            {
                content =
                    _javaDocPatternReturn.Replace(content, new MatchEvaluator(delegate(Match match)
                    {
                        return "<returns>" + match.Groups[1].Value + "</returns>";
                    }));
            }
            // Replacing the authors
            if (_javaDocPatternAuthor.IsMatch(content))
            {
                content =
                    _javaDocPatternAuthor.Replace(content, new MatchEvaluator(delegate(Match match)
                    {
                        return "<author>" + match.Groups[1].Value + "</author>";
                    }));
            }

            #endregion

            #region Correcting XmlComments

            if (_xmlCommentsEntireTag.IsMatch(content))
            {
                content =
                    _xmlCommentsEntireTag.Replace(content, new MatchEvaluator(delegate(Match match)
                        {
                            String bareDescription = match.Groups[2].Value;

                            // Searching for the tag and its tabulation
                            String markupTabulation =
                                _xmlCommentsMarkup.Match(match.Value).Value;

                            #region Entries validation

		                    // Identifing elements without comments
                            if (bareDescription.StartsWith("<"))
                            {
                                return match.Value;
                            }
                            if (!_xmlCommentsJustElement.IsMatch(match.Value))
                            {
                                return
                                    markupTabulation + "<summary>\n" +
                                    markupTabulation + bareDescription + "\n" +
                                    markupTabulation + "</summary>";
                            }

		                    #endregion

                            // Seaching for the start of elements
                            int startElementIndex = _xmlCommentsJustElement.Match(bareDescription).Index;

                            // Getting the description
                            String description =
                                bareDescription.Substring(0, startElementIndex);

                            // Getting the elements
                            String elements =
                                bareDescription.Substring(
                                    startElementIndex,
                                    bareDescription.Length - startElementIndex);

                            // Including summary tags
                            String retorno =
                                markupTabulation + "<summary>" +
                                markupTabulation + description +
                                markupTabulation + "</summary>" +
                                elements;

                            return retorno;
                        }));
            }
        
            #endregion

            return content;
        }
    }
}
